#include "ej_bsp_spi.h"

/*---------------------------- Internal Configuration --------------------------*/
#define MAX_BUSES       4   // 最大支持总线数量
#define MAX_DEVICES     8   // 最大支持设备数量

/*---------------------------- Internal Data Structures ------------------------*/
static struct {
    spi_bus_t buses[MAX_BUSES];       // 总线实例池
    spi_device_t devices[MAX_DEVICES]; // 设备实例池
    uint8_t bus_count;                // 已注册总线数量
    uint8_t device_count;             // 已挂载设备数量
} spi_manager = {0};

/*---------------------------- Internal Helper Functions -----------------------*/
static spi_bus_t* find_bus(const char *bus_name) {
    for (uint8_t i = 0; i < spi_manager.bus_count; i++) {
        if (strcmp(spi_manager.buses[i].bus_name, bus_name) == 0) {
            return &spi_manager.buses[i];
        }
    }
    return NULL;
}

static spi_device_t* find_device(const char *dev_name) {
    for (uint8_t i = 0; i < spi_manager.device_count; i++) {
        if (strcmp(spi_manager.devices[i].dev_name, dev_name) == 0) {
            return &spi_manager.devices[i];
        }
    }
    return NULL;
}

/*---------------------------- Software SPI Implementation --------------------*/
// 发送/接收一个字节 (软件SPI)
static uint8_t sw_spi_transfer_byte(spi_bus_t *bus, uint8_t tx_byte) {
    uint8_t rx_byte = 0;
    sw_spi_cfg_t *cfg = &bus->drv_info.cfg.sw;
    
    // 根据位顺序处理数据
    if (cfg->bit_order == SPI_MSB_FIRST) {
        for (int8_t i = 7; i >= 0; i--) {
            uint8_t bit = (tx_byte >> i) & 0x01;
            
            // MOSI设置
            cfg->mosi_set(bit);
            
            // 模式0和模式3需要先设置数据
            if (cfg->mode == SPI_MODE0 || cfg->mode == SPI_MODE3) {
                cfg->delay_us(cfg->clock_delay / 2);
                cfg->sck_set(1);
                cfg->delay_us(cfg->clock_delay / 2);
                rx_byte |= (cfg->miso_get() << i);
                cfg->sck_set(0);
            } 
            // 模式1和模式2需要先产生时钟边沿
            else {
                cfg->sck_set(1);
                cfg->delay_us(cfg->clock_delay / 2);
                cfg->sck_set(0);
                rx_byte |= (cfg->miso_get() << i);
                cfg->delay_us(cfg->clock_delay / 2);
            }
        }
    } 
    else { // LSB_FIRST
        for (uint8_t i = 0; i < 8; i++) {
            uint8_t bit = (tx_byte >> i) & 0x01;
            
            // MOSI设置
            cfg->mosi_set(bit);
            
            if (cfg->mode == SPI_MODE0 || cfg->mode == SPI_MODE3) {
                cfg->delay_us(cfg->clock_delay / 2);
                cfg->sck_set(1);
                cfg->delay_us(cfg->clock_delay / 2);
                rx_byte |= (cfg->miso_get() << i);
                cfg->sck_set(0);
            } else {
                cfg->sck_set(1);
                cfg->delay_us(cfg->clock_delay / 2);
                cfg->sck_set(0);
                rx_byte |= (cfg->miso_get() << i);
                cfg->delay_us(cfg->clock_delay / 2);
            }
        }
    }
    
    return rx_byte;
}

/*---------------------------- Public API Implementation -----------------------*/
spi_status_e ej_bsp_spi_register_bus(const char *bus_name, const spi_drv_info_t *drv_info) {
    if (spi_manager.bus_count >= MAX_BUSES) return SPI_ERR_INVALID_CFG;
    if (find_bus(bus_name) != NULL) return SPI_ERR_DEVICE_EXISTS;

    spi_bus_t *bus = &spi_manager.buses[spi_manager.bus_count];
    bus->bus_name = bus_name;
    bus->drv_info = *drv_info;
    bus->initialized = FALSE;
    spi_manager.bus_count++;
    return SPI_OK;
}

spi_status_e ej_bsp_spi_init_bus(const char *bus_name) {
    spi_bus_t *bus = find_bus(bus_name);
    if (!bus) return SPI_ERR_BUS_NOT_FOUND;

    // 硬件模式初始化
    if (bus->drv_info.mode == SPI_MODE_HW) {
        if (bus->drv_info.cfg.hw.ops.init) {
            bus->drv_info.cfg.hw.ops.init();
        }
    }
    // 软件模式初始化
    else if (bus->drv_info.mode == SPI_MODE_SW) {
        sw_spi_cfg_t *sw_cfg = &bus->drv_info.cfg.sw;
        if (!sw_cfg->sck_set || !sw_cfg->mosi_set || 
            !sw_cfg->miso_get || !sw_cfg->delay_us) {
            return SPI_ERR_INVALID_CFG;
        }
        
        // 初始状态设置
        sw_cfg->sck_set(sw_cfg->mode == SPI_MODE0 || sw_cfg->mode == SPI_MODE1 ? 0 : 1);
        sw_cfg->mosi_set(1); // 空闲时MOSI通常为高
    }
    
    bus->initialized = TRUE;
    return SPI_OK;
}

spi_status_e ej_bsp_spi_attach_device(const char *bus_name, const char *dev_name, uint8_t cs_pin) {
    if (spi_manager.device_count >= MAX_DEVICES) return SPI_ERR_INVALID_CFG;
    if (find_device(dev_name)) return SPI_ERR_DEVICE_EXISTS;
    if (!find_bus(bus_name)) return SPI_ERR_BUS_NOT_FOUND;

    spi_device_t *dev = &spi_manager.devices[spi_manager.device_count];
    dev->dev_name = dev_name;
    dev->bus_name = bus_name;
    dev->cs_pin = cs_pin;
    spi_manager.device_count++;
    return SPI_OK;
}

spi_status_e ej_bsp_spi_transfer(const char *dev_name, 
                               const uint8_t *tx_data, uint16_t tx_len,
                               uint8_t *rx_data, uint16_t rx_len) 
{
    spi_device_t *dev = find_device(dev_name);
    if (!dev) return SPI_ERR_DEVICE_NOT_FOUND;
    
    spi_bus_t *bus = find_bus(dev->bus_name);
    if (!bus || !bus->initialized) return SPI_ERR_BUS_NOT_INIT;
    
    // 硬件模式传输
    if (bus->drv_info.mode == SPI_MODE_HW) {
        hw_spi_cfg_t *hw_cfg = &bus->drv_info.cfg.hw;
        
        // 激活片选
        if (hw_cfg->ops.cs_set) {
            hw_cfg->ops.cs_set(dev->cs_pin, 0);
        }
        
        if (hw_cfg->ops.transfer) {
            spi_status_e status = hw_cfg->ops.transfer(tx_data, tx_len, rx_data, rx_len);
            
            // 释放片选
            if (hw_cfg->ops.cs_set) {
                hw_cfg->ops.cs_set(dev->cs_pin, 1);
            }
            
            return status;
        }
        return SPI_ERR_INVALID_CFG;
    }
    // 软件模式传输
    else {
        sw_spi_cfg_t *cfg = &bus->drv_info.cfg.sw;
        
        // 激活片选
        if (cfg->cs_set) {
            cfg->cs_set(0);
        }
        
        // 计算最大传输长度
        uint16_t max_len = (tx_len > rx_len) ? tx_len : rx_len;
        
        // 全双工传输
        for (uint16_t i = 0; i < max_len; i++) {
            uint8_t tx_byte = 0xFF; // 默认发送0xFF
            
            // 如果有要发送的数据
            if (tx_data && i < tx_len) {
                tx_byte = tx_data[i];
            }
            
            uint8_t rx_byte = sw_spi_transfer_byte(bus, tx_byte);
            
            // 如果有接收缓冲区且当前在接收范围内
            if (rx_data && i < rx_len) {
                rx_data[i] = rx_byte;
            }
        }
        
        // 释放片选
        if (cfg->cs_set) {
            cfg->cs_set(1);
        }
        
        return SPI_OK;
    }
}

/*---------------------------- Expand API Implementation ----------------------*/
spi_status_e ej_bsp_spi_write(const char *dev_name, const uint8_t *data, uint16_t len) 
{
    return ej_bsp_spi_transfer(dev_name, data, len, NULL, 0);
}

spi_status_e ej_bsp_spi_read(const char *dev_name, uint8_t *data, uint16_t len) 
{
    return ej_bsp_spi_transfer(dev_name, NULL, 0, data, len);
}

spi_status_e ej_bsp_spi_reg_write(const char *dev_name, uint8_t reg, 
                                const uint8_t *data, uint16_t len) {
    if (!data || len == 0) return SPI_ERR_NOT_PARAM;
    
    // 创建包含寄存器和数据的缓冲区
    uint8_t *buffer = (uint8_t*)malloc(len + 1);
    if (!buffer) return SPI_ERR_INVALID_CFG;
    
    buffer[0] = reg;
    memcpy(buffer + 1, data, len);
    
    spi_status_e status = ej_bsp_spi_write(dev_name, buffer, len + 1);
    free(buffer);
    return status;
}

spi_status_e ej_bsp_spi_reg_read(const char *dev_name, uint8_t reg, 
                               uint8_t *data, uint16_t len) {
    if (!data || len == 0) return SPI_ERR_NOT_PARAM;
    
    // 先发送寄存器地址
    spi_status_e status = ej_bsp_spi_write(dev_name, &reg, 1);
    if (status != SPI_OK) return status;
    
    // 然后读取数据
    return ej_bsp_spi_read(dev_name, data, len);
}

